//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<IData.cpp>
///	@path	~/src/database/
///	@date	2007/11/25
///	@desc	Data entry interface.

#include "config/config.h"

#include "object/IBuffer.h"

#include "database/IData.h"

namespace xeres {

	IMPL_IOBJECT_INTERFACE( IData );

	// ctor
	IData::IData( void )
	{
	}

	// dtor
	IData::~IData( void )
	{
	}

	// DuplicateFrom
	bool IData::DuplicateFrom( const Ref<IVar>& val )
	{
		TRACE_WARNING( _S("Data Entry disabled duplication.") );
		return false;
	}

	// SetBool
	bool IData::SetBool( bool val )
	{
		TRACE_ERROR( _S("%s::SetBool: This function is not implemented.") , GetClassName() );
		return false;
	}

	// SetInt
	bool IData::SetInt( int val )
	{
		TRACE_ERROR( _S("%s::SetInt: This function is not implemented.") , GetClassName() );
		return false;
	}

	// SetFloat
	bool IData::SetFloat( float val )
	{
		TRACE_ERROR( _S("%s::SetFloat: This function is not implemented.") , GetClassName() );
		return false;
	}

	// SetPair
	bool IData::SetPair( const Pair<float>& val )
	{
		TRACE_ERROR( _S("%s::SetPair: This function is not implemented.") , GetClassName() );
		return false;
	}

	// SetVector
	bool IData::SetVector( const Vector<float>& val )
	{
		TRACE_ERROR( _S("%s::SetVector: This function is not implemented.") , GetClassName() );
		return false;
	}

	// SetQuat
	bool IData::SetQuat( const Quat<float>& val )
	{
		TRACE_ERROR( _S("%s::SetQuat: This function is not implemented.") , GetClassName() );
		return false;
	}

	// SetColor
	bool IData::SetColor( const Color4& val )
	{
		TRACE_ERROR( _S("%s::SetColor: This function is not implemented.") , GetClassName() );
		return false;
	}

	// SetMatrix
	bool IData::SetMatrix( const Matrix<float>& val )
	{
		TRACE_ERROR( _S("%s::SetMatrix: This function is not implemented.") , GetClassName() );
		return false;
	}

	// SetString
	bool IData::SetString( const WString& val )
	{
		TRACE_ERROR( _S("%s::SetString: This function is not implemented.") , GetClassName() );
		return false;
	}

	// SetObject
	bool IData::SetObject( RefWeak<IObject> val )
	{
		TRACE_ERROR( _S("%s::SetObject: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetBool
	bool IData::GetBool( bool& val ) const
	{
		TRACE_ERROR( _S("%s::GetBool: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetInt
	bool IData::GetInt( int& val ) const
	{
		TRACE_ERROR( _S("%s::GetInt: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetFloat
	bool IData::GetFloat( float& val ) const
	{
		TRACE_ERROR( _S("%s::GetFloat: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetPair
	bool IData::GetPair( Pair<float>& val ) const
	{
		TRACE_ERROR( _S("%s::GetPair: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetVector
	bool IData::GetVector( Vector<float>& val ) const
	{
		TRACE_ERROR( _S("%s::GetVector: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetQuat
	bool IData::GetQuat( Quat<float>& val ) const
	{
		TRACE_ERROR( _S("%s::GetQuat: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetColor
	bool IData::GetColor( Color4& val ) const
	{
		TRACE_ERROR( _S("%s::GetColor: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetMatrix
	bool IData::GetMatrix( Matrix<float>& val ) const
	{
		TRACE_ERROR( _S("%s::GetMatrix: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetString
	bool IData::GetString( WString& val ) const
	{
		TRACE_ERROR( _S("%s::GetString: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetObject
	bool IData::GetObject( Ref<IObject>& val ) const
	{
		TRACE_ERROR( _S("%s::GetObject: This function is not implemented.") , GetClassName() );
		return false;
	}

	// ReadBool
	bool IData::ReadBool( const WString& path , bool defaultVal /*= false */ )
	{
		RefPass<IData> child = OpenData( path );

		bool val = false;
		if( child.IsValid() && child->GetBool( val ) )
			return val;
		else
			return defaultVal;
	}

	// ReadInt
	int IData::ReadInt( const WString& path , int defaultVal /*= 0 */ )
	{
		RefPass<IData> child = OpenData( path );

		int val = 0;
		if( child.IsValid() && child->GetInt( val ) )
			return val;
		else
			return defaultVal;
	}

	// ReadFloat
	float IData::ReadFloat( const WString& path , float defaultVal /*= 0 */ )
	{
		RefPass<IData> child = OpenData( path );

		float val = 0;
		if( child.IsValid() && child->GetFloat( val ) )
			return val;
		else
			return defaultVal;
	}

	// ReadPair
	Pair<float> IData::ReadPair( const WString& path , const Pair<float>& defaultVal /*= Pair<float>(0) */ )
	{
		RefPass<IData> child = OpenData( path );

		Pair<float> val(0);
		if( child.IsValid() && child->GetPair( val ) )
			return val;
		else
			return defaultVal;
	}

	// ReadVector
	Vector<float> IData::ReadVector( const WString& path , const Vector<float>& defaultVal /*= Vector<float>(0) */ )
	{
		RefPass<IData> child = OpenData( path );

		Vector<float> val(0);
		if( child.IsValid() && child->GetVector( val ) )
			return val;
		else
			return defaultVal;
	}

	// ReadQuat
	Quat<float> IData::ReadQuat( const WString& path , const Quat<float>&defaultVal /*= Quat<float>(0,0,0,0) */ )
	{
		RefPass<IData> child = OpenData( path );

		Quat<float> val(0,0,0,0);
		if( child.IsValid() && child->GetQuat( val ) )
			return val;
		else
			return defaultVal;
	}

	// ReadMatrix
	Matrix<float> IData::ReadMatrix( const WString& path , const Matrix<float>& defaultVal /*= Matrix<float>() */ )
	{
		RefPass<IData> child = OpenData( path );

		Matrix<float> val;
		if( child.IsValid() && child->GetMatrix( val ) )
			return val;
		else
			return defaultVal;
	}

	// ReadColor
	Color4 IData::ReadColor( const WString& path , const Color4& defaultVal /*= Color4(0,0) */ )
	{
		RefPass<IData> child = OpenData( path );

		Color4 val(0,0);
		if( child.IsValid() && child->GetColor( val ) )
			return val;
		else
			return defaultVal;
	}

	// ReadString
	WString IData::ReadString( const WString& path , const WString& defaultVal /*= WString() */ )
	{
		RefPass<IData> child = OpenData( path );

		WString val;
		if( child.IsValid() && child->GetString( val ) )
			return val;
		else
			return defaultVal;
	}

	// ReadBuffer
	RefPass<IBuffer> IData::ReadBuffer( const WString& path , RefWeak<IBuffer> defaultVal /*= RefWeak<IBuffer>(NULL) */ )
	{
		RefPass<IData> child = OpenData( path );

		Ref<IObject> val;
		if( child.IsValid() && child->GetObject( val ) )
		{
			if( val->IsA<IBuffer>() )
			{
				RefWeak<IBuffer> buffer( val );
				return buffer->Duplciate();
			}
		}
		return defaultVal;
	}

	// WriteBool
	bool IData::WriteBool( const WString& path , bool val )
	{
		RefPass<IData> child = OpenData( path );
		return ( child.IsValid() && child->SetBool( val ) );
	}

	// WriteInt
	bool IData::WriteInt( const WString& path , int val )
	{
		RefPass<IData> child = OpenData( path );
		return ( child.IsValid() && child->SetInt( val ) );
	}

	// WriteFloat
	bool IData::WriteFloat( const WString& path , float val )
	{
		RefPass<IData> child = OpenData( path );
		return ( child.IsValid() && child->SetFloat( val ) );
	}

	// WritePair
	bool IData::WritePair( const WString& path , const Pair<float>& val )
	{
		RefPass<IData> child = OpenData( path );
		return ( child.IsValid() && child->SetPair( val ) );
	}

	// WriteVector
	bool IData::WriteVector( const WString& path , const Vector<float>& val )
	{
		RefPass<IData> child = OpenData( path );
		return ( child.IsValid() && child->SetVector( val ) );
	}

	// WriteQuat
	bool IData::WriteQuat( const WString& path , const Quat<float>& val )
	{
		RefPass<IData> child = OpenData( path );
		return ( child.IsValid() && child->SetQuat( val ) );
	}

	// WriteMatrix
	bool IData::WriteMatrix( const WString& path , const Matrix<float>& val )
	{
		RefPass<IData> child = OpenData( path );
		return ( child.IsValid() && child->SetMatrix( val ) );
	}

	// WriteColor
	bool IData::WriteColor( const WString& path , const Color4& val )
	{
		RefPass<IData> child = OpenData( path );
		return ( child.IsValid() && child->SetColor( val ) );
	}

	// WriteString
	bool IData::WriteString( const WString& path , const WString& val )
	{
		RefPass<IData> child = OpenData( path );
		return ( child.IsValid() && child->SetString( val ) );
	}

	// WriteBuffer
	bool IData::WriteBuffer( const WString& path , RefWeak<IBuffer> val )
	{
		RefPass<IData> child = OpenData( path );
		return ( child.IsValid() && child->SetObject( val ) );
	}

	template<
		typename _Type 
	> static inline void ReadArray( IData * dataentry , const WString& path , std::vector<_Type>& array )
	{
		// break strings into path
		StringSeq pathSeq;
		break_string( path , '/' , pathSeq );
		if( pathSeq.size() == 0 )
		{
			TRACE_ERROR( _S("IData::ReadArray: Path pointing to self entry is invalid.") );
			return;
		}

		// translate path into keys
		std::vector<Key> keys;
		if( !Key::QueryKeys( pathSeq , keys ) )
		{
			TRACE_ERROR( _S("IData::ReadArray: Path has undefined entry %s'.") , pathSeq[keys.size()].c_str() );
			return;
		}

		RefPass<IData> parent = dataentry->OpenDataByKeys( keys , keys.size() - 1 );
		if( parent.IsNull() )
			return;

		AccessEntry<_Type>::GetArray( RefWeak<IData>(parent) , keys.back() , array );
	}

	// ReadBools
	void IData::ReadBools( const WString& path , std::vector<bool>& bools )
	{
		TRACK_FUNCTION_SCOPE();
		ReadArray<bool>( this , path , bools );
		return;
	}

	// ReadInts
	void IData::ReadInts( const WString& path , std::vector<int>& ints )
	{
		TRACE_ERROR( _S("%s::ReadInts: This function is not implemented.") , GetClassName() );
		ReadArray<int>( this , path , ints );
		return;
	}

	// ReadFloats
	void IData::ReadFloats( const WString& path , std::vector<float>& floats )
	{
		TRACE_ERROR( _S("%s::ReadFloats: This function is not implemented.") , GetClassName() );
		ReadArray<float>( this , path , floats );
		return;
	}

	// ReadPairs
	void IData::ReadPairs( const WString& path , std::vector< Pair<float> >& pairs )
	{
		TRACE_ERROR( _S("%s::ReadPairs: This function is not implemented.") , GetClassName() );
		ReadArray< Pair<float> >( this , path , pairs );
		return;
	}

	// ReadVectors
	void IData::ReadVectors( const WString& path , std::vector< Vector<float> >& vectors )
	{
		TRACE_ERROR( _S("%s::ReadVectors: This function is not implemented.") , GetClassName() );
		ReadArray< Vector<float> >( this , path , vectors );
		return;
	}

	// ReadQuats
	void IData::ReadQuats( const WString& path , std::vector< Quat<float> >& quats )
	{
		TRACE_ERROR( _S("%s::ReadQuats: This function is not implemented.") , GetClassName() );
		ReadArray< Quat<float> >( this , path , quats );
		return;
	}

	// ReadMatrices
	void IData::ReadMatrices( const WString& path , std::vector< Matrix<float> >& matrices )
	{
		TRACE_ERROR( _S("%s::ReadMatrices: This function is not implemented.") , GetClassName() );
		ReadArray< Matrix<float> >( this , path , matrices );
		return;
	}

	// ReadColors
	void IData::ReadColors( const WString& path , std::vector<Color4>& colors )
	{
		TRACE_ERROR( _S("%s::ReadColors: This function is not implemented.") , GetClassName() );
		ReadArray<Color4>( this , path , colors );
		return;
	}

	// ReadStrings
	void IData::ReadStrings( const WString& path , std::vector<WString>& strings )
	{
		TRACE_ERROR( _S("%s::ReadStrings: This function is not implemented.") , GetClassName() );
		ReadArray<WString>( this , path , strings );
		return;
	}

	template<
		typename _Type 
	> static inline void ReadArray( IData * dataentry , const Key& key , std::vector<_Type>& array )
	{
		// search all children
		size_t index = 0;
		Ref<IData> child( NULL );
		while( ( child = dataentry->FindChild( key , index ) ).IsValid() )
		{
			_Type value;
			if( AccessEntry<_Type>::Get( child , value ) )
				array.push_back( value );
		}
	}

	// ReadBools
	void IData::ReadBools( const Key& key , std::vector<bool>& bools )
	{
		TRACE_WARNING( _S("%s::ReadBools: Using default implementation, may cause performance problem.") ,
			GetClassName() );
		ReadArray<bool>( this , key , bools );
	}

	// ReadInts
	void IData::ReadInts( const Key& key , std::vector<int>& ints )
	{
		TRACE_WARNING( _S("%s::ReadBools: Using default implementation, may cause performance problem.") ,
			GetClassName() );
		ReadArray<int>( this , key , ints );
	}

	// ReadFloats
	void IData::ReadFloats( const Key& key , std::vector<float>& floats )
	{
		TRACE_WARNING( _S("%s::ReadBools: Using default implementation, may cause performance problem.") ,
			GetClassName() );
		ReadArray<float>( this , key , floats );
	}

	// ReadPairs
	void IData::ReadPairs( const Key& key , std::vector< Pair<float> >& pairs )
	{
		TRACE_WARNING( _S("%s::ReadBools: Using default implementation, may cause performance problem.") ,
			GetClassName() );
		ReadArray< Pair<float> >( this , key , pairs );
	}

	// ReadVectors
	void IData::ReadVectors( const Key& key , std::vector< Vector<float> >& vectors )
	{
		TRACE_WARNING( _S("%s::ReadBools: Using default implementation, may cause performance problem.") ,
			GetClassName() );
		ReadArray< Vector<float> >( this , key , vectors );
	}

	// ReadQuats
	void IData::ReadQuats( const Key& key , std::vector< Quat<float> >& quats )
	{
		TRACE_WARNING( _S("%s::ReadBools: Using default implementation, may cause performance problem.") ,
			GetClassName() );
		ReadArray< Quat<float> >( this , key , quats );
	}

	// ReadMatrices
	void IData::ReadMatrices( const Key& key , std::vector< Matrix<float> >& matrices )
	{
		TRACE_WARNING( _S("%s::ReadBools: Using default implementation, may cause performance problem.") ,
			GetClassName() );
		ReadArray< Matrix<float> >( this , key , matrices );
	}

	// ReadColors
	void IData::ReadColors( const Key& key , std::vector<Color4>& colors )
	{
		TRACE_WARNING( _S("%s::ReadBools: Using default implementation, may cause performance problem.") ,
			GetClassName() );
		ReadArray<Color4>( this , key , colors );
	}

	// ReadStrings
	void IData::ReadStrings( const Key& key , std::vector<WString>& strings )
	{
		TRACE_WARNING( _S("%s::ReadBools: Using default implementation, may cause performance problem.") ,
			GetClassName() );
		ReadArray<WString>( this , key , strings );
	}

	// GetAttribute
	bool IData::GetAttribute( const WString& attr , WString& value , const WString& defaultVal )
	{
		return false;
	}

	// SetAttribute
	bool IData::SetAttribute( const WString& attr , const WString& value )
	{
		return false;
	}

	// GetAttributeCount
	size_t IData::GetAttributeCount( void )
	{
		return 0;
	}

	// AttributeBegin
	void * IData::AttributeBegin( void )
	{
		return NULL;
	}

	// AttributeIterate
	bool IData::AttributeIterate( void * context , WString& name , WString& value , bool iterateNext )
	{
		return false;
	}

	// AttributeEnd
	void IData::AttributeEnd( void * context )
	{

	}

	// AddChild
	bool IData::AddChild( RefWeak<IData> child )
	{
		TRACE_ERROR( _S("%s::AddChild: This function is not implemented.") , GetClassName() );
		return false;
	}

	// NewChild
	RefPass<IData> IData::NewChild( const Key& key )
	{
		TRACE_ERROR( _S("%s::NewChild: This function is not implemented.") , GetClassName() );
		return NULL;
	}

	// IndexOf
	bool IData::IndexOf( RefWeak<IData> child , size_t& index )
	{
		TRACE_ERROR( _S("%s::IndexOf: This function is not implemented.") , GetClassName() );
		return false;
	}

	// DeleteChild
	bool IData::DeleteChild( size_t index )
	{
		TRACE_ERROR( _S("%s::DeleteChild: This function is not implemented.") , GetClassName() );
		return false;
	}

	// DeleteChild
	bool IData::DeleteChild( RefWeak<IData> child )
	{
		TRACE_ERROR( _S("%s::DeleteChild: This function is not implemented.") , GetClassName() );
		return false;
	}

	// DeleteChild
	bool IData::DeleteChild( const Key& key )
	{
		TRACE_ERROR( _S("%s::DeleteChild: This function is not implemented.") , GetClassName() );
		return false;
	}

	// DeleteChildren
	void IData::DeleteChildren( void )
	{
		TRACE_ERROR( _S("%s::DeleteChildren: This function is not implemented.") , GetClassName() );
	}

	// DeleteChildren
	void IData::DeleteChildren( const Key& key )
	{
		TRACE_ERROR( _S("%s::DeleteChildren: This function is not implemented.") , GetClassName() );
	}

	// GetChildCount
	size_t IData::GetChildCount( void )
	{
		TRACE_ERROR( _S("%s::GetChildCount: This function is not implemented.") , GetClassName() );
		return 0;
	}

	// GetChild
	RefPass<IData> IData::GetChild( const Key& child )
	{
		TRACE_ERROR( _S("%s::GetChild: This function is not implemented.") , GetClassName() );
		return NULL;
	}

	// GetChild
	RefPass<IData> IData::GetChild( size_t index )
	{
		TRACE_ERROR( _S("%s::GetChild: This function is not implemented.") , GetClassName() );
		return NULL;
	}

	// GetChild
	RefPass<IData> IData::GetChild( const WString& name )
	{
		// In default implementation, we dispatch it to GetChild by key.
		Key key = Key::QueryKey( name );
		if( !key.IsValid() )
			return NULL;
		return GetChild( key );
	}

	// GetChildInfo
	bool IData::GetChildInfo( const Key& child , DataInfo& info )
	{
		TRACE_ERROR( _S("%s::GetChildInfo: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetChildInfo
	bool IData::GetChildInfo( size_t index , DataInfo& info , WString& name )
	{
		TRACE_ERROR( _S("%s::GetChildInfo: This function is not implemented.") , GetClassName() );
		return false;
	}

	// GetChildInfo
	bool IData::GetChildInfo( const WString& name , DataInfo& info )
	{
		// In default implementation, we dispatch it to GetChildInfo by key.
		Key key = Key::QueryKey( name );
		if( !key.IsValid() )
			return false;
		return GetChildInfo( key , info );
	}

	// FindChild
	RefPass<IData> IData::FindChild( const Key& key , size_t& index )
	{
		TRACE_ERROR( _S("%s::FindChild: This function is not implemented.") , GetClassName() );
		return NULL;
	}

	// FindChild
	RefPass<IData> IData::FindChild( const WString& name , size_t& index )
	{
		// In default implementation, we dispatch it to FindChild by key.
		Key key = Key::QueryKey( name );
		if( !key.IsValid() )
			return NULL;
		return FindChild( key , index );
	}

	// FindChildIndex
	bool IData::FindChildIndex( const Key& child , size_t& index )
	{
		TRACE_ERROR( _S("%s::FindChildIndex: This function is not implemented.") , GetClassName() );
		return false;
	}

	// FindChildIndex
	bool IData::FindChildIndex( const WString& name , size_t& index )
	{
		// In default implementation, we dispatch it to FindChildIndex by key.
		Key key = Key::QueryKey( name );
		if( !key.IsValid() )
			return false;
		return FindChildIndex( key , index );
	}

	// OpenData
	RefPass<IData> IData::OpenData( const WString& path , bool create_non_exist /*= false */ )
	{
		TRACK_FUNCTION_SCOPE();

		// break strings into path
		StringSeq pathSeq;
		break_string( path , '/' , pathSeq );

		while( pathSeq.front() == _S(".") )
		{
			TRACE_WARNING( _S("IData::OpenData: It's not recommended to use '.' represent current directory.") );
			pathSeq.pop_front();
			if( pathSeq.size() == 0 )
				break;
		}

		if( pathSeq.size() == 0 )
		{
			TRACE_ERROR( _S("IData::OpenData: Empty path points to no valid entry.") );
			return NULL;
		}

		// dig it one by one, deeper & deeper
		RefPass<IData> parent(this);
		for( size_t i = 0 , total = pathSeq.size() ; i < total ; ++i )
		{
			RefPass<IData> child = parent->GetChild( pathSeq[i] );
			if( !child.IsValid() )
			{
				if( create_non_exist )
				{
					// registered new key
					child = parent->NewChild( Key::MakeKey( pathSeq[i] ) );
				}
				else
				{
					TRACE_ERROR( _S("IData::OpenDataByKeys: No child matches key '%s' in '%s'.") ,
						pathSeq[i].c_str() , path.c_str() );
					return NULL;
				}
			}
			parent = child;
		}
		return parent;
	}

	// OpenDataArray
	void IData::OpenDataArray( const WString& path , std::vector< Ref<IData> >& entries )
	{
		TRACK_FUNCTION_SCOPE();

		// break strings into path
		StringSeq pathSeq;
		break_string( path , '/' , pathSeq );

		while( pathSeq.front() == _S(".") )
		{
			TRACE_WARNING( _S("IData::OpenDataArray: It's not recommended to use '.' represent current directory.") );
			pathSeq.pop_front();
			if( pathSeq.size() == 0 )
				break;
		}

		if( pathSeq.size() == 0 )
		{
			TRACE_ERROR( _S("IData::OpenDataArray: Empty path points to no valid entry.") );
			return;
		}

		// dig it one by one, deeper & deeper
		RefPass<IData> parent(this);
		for( size_t i = 0 , total = pathSeq.size() - 1 ; i < total ; ++i )
		{
			RefPass<IData> child = parent->GetChild( pathSeq[i] );
			if( !child.IsValid() )
			{
				TRACE_ERROR( _S("IData::OpenDataByKeys: No child matches key '%s' in '%s'.") ,
					pathSeq[i].c_str() , path.c_str() );
				return;
			}
			parent = child;
		}

		size_t index = 0;
		RefPass<IData> entry = parent->FindChild( pathSeq.back() , index );
		while( entry.IsValid() )
		{
			entries.push_back( entry );
			entry = parent->FindChild( pathSeq.back() , index );
		}
	}

	// OpenDataByKeys
	RefPass<IData> IData::OpenDataByKeys( const std::vector<Key>& keys , size_t limit /* = 0 */ )
	{
		TRACK_FUNCTION_SCOPE();

		size_t total = limit == 0 ? keys.size() : limit;

		RefPass<IData> parent(this);
		// one by one step in
		for( size_t i = 0 ; i < total ; ++i )
		{
			parent = parent->GetChild( keys[i] );
			if( parent.IsNull() )
			{
				TRACE_ERROR( _S("IData::OpenDataByKeys: No child matches key '%s'.") , keys[i].GetCStr() );
				return NULL;
			}
		}
		return parent;
	}

} // namespace xeres
